﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharedLib.BasicServices.MessageFramework;
using Tracy.DataModel;
using Tracy.Messages;
using System.Xml;
using System.Collections.ObjectModel;
using Tracy.BasicServices;


namespace Tracy.Handlers
{
    public class FeedScanHandler : TaskMessageHandler
    {
        MessageCallback getXmlCallback;
        //private object _lockHelperURLMapping = new object();
        private object _lockHelperXmlHandling = new object();//TODO: thread sync need a better solution

        //The mapping for URL, FeedSources and Entries
        //TODO: convert to static?
        private IDictionary<string, IDictionary<FeedSource, ICollection<Entry>>> _processingURLMapping = new Dictionary<string, IDictionary<FeedSource, ICollection<Entry>>>();

        private IDictionary<string, IDictionary<FeedSource, ICollection<Entry>>> ProcessingURLMapping
        {
            get {
                //lock (_lockHelperURLMapping)
                //{
                    return _processingURLMapping;
                //}
            }
        }
        private IDictionary<FeedSource, ISourceParser> _sourceParserCache = new Dictionary<FeedSource, ISourceParser>();

        private IDictionary<FeedSource, ISourceParser> SourceParserCache
        {
            get {

                return _sourceParserCache; 
            }
        }

        public FeedScanHandler()
        {
            getXmlCallback = new MessageCallback(this.OnXmlRetrieved);
        }
        
        protected override void ProcessMessage(Messages.TaskMessage msg)
        {
            lock (_lockHelperXmlHandling)
            {
                base.ProcessMessage(msg);

                //Collect and build url-feedsource-entry mapping
                foreach (FeedSource source in TracyBus.Instance.ConfigurationManager.FeedSourceProvider.GetItems)
                {
                    List<Entry> entriesToScan;
                    if (msg.Data != null && msg.Data is Entry)
                    {
                        entriesToScan = new List<Entry>();
                        entriesToScan.Add((Entry)msg.Data);
                    }
                    else
                    {
                        entriesToScan = TracyBus.Instance.EntryProvider.GetItems();
                    }

                    foreach (Entry entry in entriesToScan)
                    {
                        string url = source.GenerateUrl(entry);
                        IDictionary<FeedSource, ICollection<Entry>> sourceDic;
                        ICollection<Entry> entryList;
                        if (!ProcessingURLMapping.ContainsKey(url))
                        {
                            sourceDic = new Dictionary<FeedSource, ICollection<Entry>>();
                            ProcessingURLMapping.Add(url, sourceDic);
                        }
                        else
                        {
                            sourceDic = ProcessingURLMapping[url];

                        }

                        if (!sourceDic.ContainsKey(source))
                        {
                            entryList = new Collection<Entry>();
                            sourceDic.Add(source, entryList);
                        }
                        else
                        {
                            entryList = sourceDic[source];
                        }
                        entryList.Add(entry);

                    }
                }

                //Dispatch message
                foreach (string url in ProcessingURLMapping.Keys)
                {
                    TracyBus.Instance.MessageDispatcher.EnqueueMessage(new GetXmlFromURLMessage(this, url, getXmlCallback));
                }
            }

        }
        
        private void OnXmlRetrieved(IAppMessage msg)
        {
            lock (_lockHelperXmlHandling)
            {
                //TODO: handler exception
                if (msg != null && msg is GetXmlFromURLMessage)
                {
                    if (msg.Exception == null)
                    {
                        XmlDocument doc = msg.Result as XmlDocument;

                        if (ProcessingURLMapping.ContainsKey(msg.Data as string))
                        {
                            IDictionary<FeedSource, ICollection<Entry>> sourceDic = ProcessingURLMapping[msg.Data as string];
                            foreach (FeedSource source in sourceDic.Keys)
                            {
                                ISourceParser parser = GetSourceParser(source);

                                XmlDocument resultDoc = parser.GetRawResources(source, doc);

                                List<Resource> result = ResourceFilter.FilterRawResources(resultDoc, sourceDic[source]);
                                List<Resource> newItemsFound = ProcessRetrievedResources(result);

                                //Notify UI
                                if (newItemsFound.Count > 0)
                                    TracyBus.Instance.MessageDispatcher.NotifyUI(msg, NotifyUIEventArgs.FOUND_RESOURCE, newItemsFound);
                            }
                        }//TODO:Exception
                    }
                    else
                    {
                        //TODO: Notify UI about the exception (put into message dispatcher)
                    }
                }
            }
        }

        private static List<Resource> ProcessRetrievedResources(List<Resource> result)
        {
            List<Resource> newItemsFound = new List<Resource>();
            List<string> resTitles = new List<string>();
            //Handle filtered resources
            foreach (Resource res in result)
            {
                if (!res.Title.Contains(res.Title) && !TracyBus.Instance.ResourceProvider.IsResourceExisting(res))
                {
                    resTitles.Add(res.Title);
                    //TracyBus.Instance.ResourceProvider.AddItem(res);
                    newItemsFound.Add(res);
                }
            }
            return newItemsFound;
        }

        

        private ISourceParser GetSourceParser(FeedSource source)
        {
            ISourceParser parser;
            if (!SourceParserCache.ContainsKey(source))
            {
                parser = TracyBus.Instance.RegisteredObjectService.CreateInstance<ISourceParser>(source.Parser);//Defined in Sources.xml
                SourceParserCache.Add(source, parser);
            }
            else
            {
                parser = SourceParserCache[source];
            }
            return parser;
        }

    }
}
